package httpclient

import (
	"bytes"
	"context"
	"encoding/json"
	"io"
	"net/http"
	"time"
)

// Client HTTP客户端结构体
type Client struct {
	baseURL    string
	httpClient *http.Client
	maxRetries int
	retryDelay time.Duration
}

// NewClient 创建新的HTTP客户端
func NewClient(baseURL string, timeout time.Duration, maxRetries int, retryDelay time.Duration) *Client {
	return &Client{
		baseURL: baseURL,
		httpClient: &http.Client{
			Timeout: timeout,
		},
		maxRetries: maxRetries,
		retryDelay: retryDelay,
	}
}

// RequestOptions 请求选项
type RequestOptions struct {
	Headers map[string]string
	Query   map[string]string
	Body    interface{}
}

// doRequest 执行HTTP请求（带重试机制）
func (c *Client) doRequest(ctx context.Context, method, path string, opts *RequestOptions) (*http.Response, error) {
	var lastErr error

	for attempt := 0; attempt <= c.maxRetries; attempt++ {
		if attempt > 0 {
			select {
			case <-ctx.Done():
				return nil, ctx.Err()
			case <-time.After(c.retryDelay):
				// 等待重试延迟
			}
		}

		// 创建请求
		req, err := c.createRequest(ctx, method, path, opts)
		if err != nil {
			return nil, err
		}

		// 执行请求
		resp, err := c.httpClient.Do(req)
		if err != nil {
			lastErr = err
			continue
		}

		// 2xx状态码表示成功
		if resp.StatusCode >= http.StatusOK && resp.StatusCode < http.StatusMultipleChoices {
			return resp, nil
		}

		// 非2xx状态码，关闭响应体并重试
		resp.Body.Close()
		lastErr = &HTTPError{
			StatusCode: resp.StatusCode,
			Message:    http.StatusText(resp.StatusCode),
		}
	}

	return nil, lastErr
}

// createRequest 创建HTTP请求
func (c *Client) createRequest(ctx context.Context, method, path string, opts *RequestOptions) (*http.Request, error) {
	var body io.Reader
	if opts != nil && opts.Body != nil {
		jsonData, err := json.Marshal(opts.Body)
		if err != nil {
			return nil, err
		}
		body = bytes.NewBuffer(jsonData)
	}

	req, err := http.NewRequestWithContext(ctx, method, c.baseURL+path, body)
	if err != nil {
		return nil, err
	}

	// 设置请求头
	if opts != nil {
		// 默认Content-Type
		if _, ok := opts.Headers["Content-Type"]; !ok && body != nil {
			req.Header.Set("Content-Type", "application/json")
		}

		for k, v := range opts.Headers {
			req.Header.Set(k, v)
		}

		// 设置查询参数
		if opts.Query != nil {
			q := req.URL.Query()
			for k, v := range opts.Query {
				q.Add(k, v)
			}
			req.URL.RawQuery = q.Encode()
		}
	}

	return req, nil
}

// Get 执行GET请求
func (c *Client) Get(ctx context.Context, path string, opts *RequestOptions) (*http.Response, error) {
	return c.doRequest(ctx, http.MethodGet, path, opts)
}

// Post 执行POST请求
func (c *Client) Post(ctx context.Context, path string, opts *RequestOptions) (*http.Response, error) {
	return c.doRequest(ctx, http.MethodPost, path, opts)
}

// Delete 执行DELETE请求
func (c *Client) Delete(ctx context.Context, path string, opts *RequestOptions) (*http.Response, error) {
	return c.doRequest(ctx, http.MethodDelete, path, opts)
}

// HTTPError HTTP错误
type HTTPError struct {
	StatusCode int
	Message    string
}

func (e *HTTPError) Error() string {
	return e.Message
}

// DecodeJSON 解码JSON响应
func DecodeJSON(resp *http.Response, v interface{}) error {
	defer resp.Body.Close()
	return json.NewDecoder(resp.Body).Decode(v)
}
